$('*[data-href]').click(
      function() {
         location.href = $(this).attr('data-href');
      }
   );

$('*[data-confirm-href]').click(
      function() {
         if (confirm("Are you sure you want to do this?")) {
            location.href = $(this).attr('data-confirm-href');
            return false;
         }
      }
   );
/**
 * Focus to select all text on inputs
 */
$('input').filter('[type=text],[type=password]')
   .click(
      function() {
         this.select();
      }
   )
   .focus(
      function() {
         $(this).click();
      }
   );

/**
 * Functions
 */
$.fn.hasAttr = function(name) {
   return this.attr(name) !== undefined;
}

function array_equal(array1,array2) {
   return !(array1 < array2 || array1 > array2)
}


$.fn.keyup_change = function(callback) {
      var $this = $(this);
      var attr = 'data-previous_value';
      var callback;
      var $keyup_changes;

      if (!$this.length) {
         return $this;
      }

      if (!$this.hasAttr(attr)) {
         $this.attr(attr,$this.val());
      }

      if (!callback) {
         $this.attr(attr,$this.val());
         $this.keyup() && $this.change();
         return $this;
      }

      $this.each(
            function() {
               $(this).change(callback);
            }
         );


      if (!$this.data('add_keyup_change_callbacks'))
         $this.data( 'add_keyup_change_callbacks', [] );

      $keyup_changes = $this.data('add_keyup_change_callbacks');

      $keyup_changes[$keyup_changes.length] = callback;

      if (!$this.data('add_keyup_change_keyup')) {
         $this.data(
               'add_keyup_change_keyup',
               function(e) {
                  if ($this.attr(attr) != $this.val()) {
                     $this.change();
                     $this.attr(attr,$this.val());
                  }
               }
            );
         $this.keyup($this.data('add_keyup_change_keyup'));
      }

     return $this;

   }

$.fn.unbind_keyup_change = function () {
      var $this = $(this);
      for (var x in $this.data('add_keyup_change_callbacks')) {
         $this.unbind('change', $this.data('add_keyup_change_callbacks')[x]);
      }
      $this.unbind('keyup', $this.data('add_keyup_change_keyup'));
   }

$.fn.first_time_change = function(callback) {
      var $this = $(this);
      var attr = 'data-val_changed';

      if (!$this.hasAttr(attr)) {
         $this.keyup_change(callback);
         $this.keyup_change(
               function (e) {
                  $this.unbind_keyup_change();
               }
            );
      }
   }

// Backward compatibility for 0.0
$.fn.firstime_change = $.fn.first_time_change;

$.fn.val_sync = function(selector, callback) {
      var $this = $(this);
      var $partner = $(selector);
      var get_value = $this.is('input, textarea, select, button') ? function() { return $this.val() } : function() { return $this.text() };
      var sync = $partner.is('input, textarea, select, button')
         ? function(text) { var result = $partner.val(text); $partner.change(); return result; }
         : function(text) { return $partner.text(text) };

      if (!callback) {
         callback = function(value) { return value };
      }

      sync(callback(get_value()));

      if (!$this.has_val()) {
         $this.bind('DOMSubtreeModified',function() {
                  sync(callback(get_value()));
               }
            );
      }

      $this.keyup_change(
            function() {
               sync(callback(get_value()));
            }
         );
   }

$.fn.key_combination = function (shortcut,callback) {
      var shortcut,callback;
      var keys = shortcut.split(/\s*\+\s*/);
      var empty_key_codes = {keys:[],modifiers:[]};
      var key_codes = {keys:[],modifers:[]};
      var modifier_keys = [];

      modifier_keys[16] = 'SHIFT';
      modifier_keys[17]  = 'CTRL';
      modifier_keys[18]   = 'ALT';

      var key_codes_pressed = empty_key_codes;

      for (var x in keys) {
         var key = keys[x].toUpperCase();
         if (key.length == 1) {
            key_codes.keys.push(key.charCodeAt(0));
         }
         else {
            key = modifier_keys.indexOf(key);
            key_codes.modifers.push(key);
         }
      }


      $(this).keydown(
            function(e) {
               key_codes_pressed.keys.length >= key_codes.keys.length && key_codes_pressed.keys.shift();


               if (modifier_keys[e.keyCode]) {
                  if (key_codes_pressed.modifiers.indexOf(e.keyCode) == -1) {
                     key_codes_pressed.modifiers.push(e.keyCode);
                     key_codes_pressed.modifiers.sort();
                  }
               }
               else
                  key_codes_pressed.keys.push(e.keyCode);


               if (array_equal(key_codes.keys,key_codes_pressed.keys) && array_equal(key_codes_pressed.modifiers,key_codes.modifers)) {
                  return callback(e);
               }

            }
         );

      $(this).keyup(
            function(e) {
               var modifier_index, key_index;
               modifier_index = key_codes_pressed.modifiers.indexOf(e.keyCode);
               if (modifier_index > -1) {
                  key_codes_pressed.modifiers.splice(modifier_index,1);
               }
               if (!key_codes_pressed.modifiers.length) {
                  key_codes_pressed.keys = [];
               }
            }
         );
   }

$.fn.disallow_paste = function() {
      var $this = $(this);
      $this.keyup(
            function() {
               $(this).key_combination('ctrl+v',function() { return false });
               $(this).context_menu(function(e) { return false; });
            }
         );
   }

$.fn.disallow_copy = function() {
      $(this).key_combination('ctrl+c',function(e) { try {e.preventDefault();} catch(e) {} return false; });
      $(this).context_menu(function(e) { return false; });
   }

$.fn.context_menu = function(callback) {
      var callback;
      var $this = $(this);
      return $this.bind(
            "contextmenu",
            function(e) {
               if (e.which === 3) {
                  return callback(e)
               }
            }
         );
   }

$.fn.return_key = function (callback) {
      return $(this).keydown(
            function(e) {
               if (e.keyCode === 13) {
                  return callback();
               }
            }
         );
   }

$.fn.next_step = function (selector,callback) {
   var selector,callback;
   var $this = $(this);

   var steps = $this.get_steps(selector);

   if (steps.$next_step.length) {
      steps.$current_steps.fadeOut(
            'fast',
            function () {
               steps.$next_step.fadeIn();
               if (callback)
                  callback();
            }
         );
      return true;
   }
   else {
      return false;
   }
}

$.fn.prev_step = function (selector,callback) {
   var selector,callback;
   var $this = $(this);

   var steps = $this.get_steps(selector);

   if (steps.$prev_step.length) {
      steps.$current_steps.fadeOut(
            'fast',
            function () {
               steps.$prev_step.fadeIn();
               if (callback)
                  callback();
            }
         );
      return true;
   }
   else {
      return false;
   }
}

$.fn.get_steps = function (selector) {
   var selector;
   var $this = $(this);

   if (!selector) {
      selector = ".step";
      var $steps = $this.find(selector);
      if (!$steps.length) {
         $steps = $this.find('> *');
      }
   }
   else {
      var $steps = $this.find(selector);
   }

   var $current_steps = $steps.filter(':visible');

   var steps = {
         $steps: $steps,
         $current_steps: $current_steps,
         $prev_step: $current_steps.prevAll(selector).eq(0).not(':visible').eq(0),
         $next_step: $current_steps.nextAll(selector).eq(0).not(':visible').eq(0)
      };

   return steps;
}

/**
 * Makes the element divided by steps
 *
 * @param string selector (jquery) of the steps, relative
 *
 */
$.fn.steps = function (selector, check_steps) {
   var selector;
   var $this = $(this);
   var $this_form = $this.filter('form');
   var $this_not_form = $this.not('form');
   var steps = $this.get_steps(selector);
   var $form_submit_buttons = $this_form.find('button[type=submit],input[type=submit]').not('.next_step');
   var $steps_navigation = '<div class="steps_navigation" ><a class="prev_step">Back</a> <a class="next_step">Next</a></div>';

   if (!$this.find('.next_step, .prev_step').length) {
      if ($this_form && $form_submit_buttons) {
         $form_submit_buttons.before($steps_navigation);
      }
      else {
         $this.append($steps_navigation);
      }
   }

   var check_steps;

   if (!check_steps) {
      check_steps = function () {
         var steps = $this.get_steps(selector);
         if (steps.$prev_step.length) {
            $this.find('.prev_step').show();
         }
         else {
            $this.find('.prev_step').hide();
         }

         // Final step
         if (!steps.$next_step.length) {
            $this.find('.next_step').hide()
            $form_submit_buttons.show();
         }
         else {
            $this.find('.next_step').show()
            $form_submit_buttons.hide();
         }
      }
   }

   $this_form.submit(
         function() {
            var $this = $(this);
            var steps = $this.get_steps(selector);

            // Do not go to next step if there is errors
            if (steps.$current_steps.find('.error:visible').length)
               return false;

            if ($this.next_step(selector,check_steps)) {
               return false;
            }

         }
      );

   $this.find('.next_step').click(
         function () {
            $this_form.submit();
            $this_not_form.next_step(selector);
            return false;
         }
      );

   $this.find('.prev_step').click(
         function() {
            $this.prev_step(selector,check_steps)
         }
      );

   $this_form.find('input[type=submit]').hide();

   steps.$current_steps.filter(':gt(0)').hide();

}

/**
 * Checks if the first element has val() attribute (even if it is blank
 */
$.fn.has_val = function() {
   return $($(this)[0]).is('input, textarea, select');
}

/**
 * html_val()
 * If there is val(), return val(), if there is html() return html() (regardless if they are blank)
 */
$.fn.html_val = function(new_value) {
   var $this = $(this);
   var new_value;

   if (new_value !== undefined) {
      if ($this.has_val()) {
         var result = $this.val(new_value);
         $this.change();
         return result;
      }
      else {
         return $this.html(new_value);
      }
   }

   if ($this.has_val()) {
      return $this.val();
   }
   else {
      return $this.html();
   }

}

$.fn.html_val_float = function(new_value) {
   var new_value;

   if (!new_value && new_value !== undefined) {
      new_value = 0;
   }
   else if (new_value) {
      new_value = parseFloat(new_value);
   }

   var html_val = $(this).html_val(new_value);

   return html_val ? parseFloat(html_val) : 0;

}


/* Calculation functions */
/**
 * Calculates sum of all html_val() of all elements, then put it in the _selector_ element
 *
 * @param string selector the target element to put the sum into
 *
 */
$.fn.sum = function (selector) {
   var selector;
   var $elements = $(this);
   var sum = 0;

   $elements.each(
         function (i) {
            sum += $(this).html_val_float();
         }
      );

   if (selector) {
      $(selector).html_val_float(sum);
   }

   return sum;
}